package com.haima.sage.bigdata.api.process;

import com.haima.sage.bigdata.api.common.Constants;
import com.haima.sage.bigdata.api.common.EsUtils;
import com.haima.sage.bigdata.api.entity.storage.Storage;
import com.haima.sage.bigdata.api.exception.ValidateException;
import com.haima.sage.bigdata.api.vo.BaseParam;
import com.haima.sage.bigdata.api.vo.param.order.OrderType;
import com.haima.sage.bigdata.api.vo.param.where.WhereCondition;
import com.haima.sage.bigdata.api.vo.param.where.WhereConditionGroup;
import com.haima.sage.bigdata.api.vo.param.where.WhereConditionItem;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.List;
import java.util.Map;

public abstract class ParamProcess {
    private static final Logger LOG = LogManager.getLogger(ParamProcess.class);
    protected EsUtils esUtils = new EsUtils();

    protected boolean isValid(List<String> list) {
        if (list == null) {
            return false;
        }
        if (list.size() == 0) {
            return false;
        }
        for (String item : list) {
            if (item == null || item.trim().length() == 0) {
                return false;
            }
        }
        return true;
    }

    protected void appendWhere(StringBuilder sql, WhereCondition where) throws ValidateException {
        if (where != null) {
            sql.append(" WHERE ");
            appendWhereCondition(where, sql);
        }
    }

    protected void appendLimit(StringBuilder sql, Integer limit, Integer maxBatchSize) {
        sql.append(" limit ");
        if (limit > maxBatchSize) {
            sql.append(maxBatchSize);
        } else {
            sql.append(limit);
        }
    }

    protected void appendOrderBy(StringBuilder sql, Map<String, OrderType> orderBy) {
        if (orderBy != null && orderBy.size() > 0) {
            sql.append(" order by ");
            for (Map.Entry<String, OrderType> entry : orderBy.entrySet()) {
                sql.append(entry.getKey());
                if (entry.getValue() != null) {
                    sql.append(" ").append(entry.getValue());
                }
                sql.append(",");
            }
            sql.deleteCharAt(sql.length() - 1);
        }


    }

    protected void appendWhereCondition(WhereCondition where, StringBuilder sql) throws ValidateException {
        if (where instanceof WhereConditionGroup) {
            int whereFirstMark = 0;
            WhereConditionGroup group = (WhereConditionGroup) where;
            if (group.getConditions() != null && group.getConditions().size() > 0) {
                sql.append("( ");
                for (WhereCondition item : group.getConditions()) {
                    whereFirstMark ++;
                    if(whereFirstMark > 1){
                        sql.append(" ").append(group.getOperator().getValue()).append(" ");
                    }
                    appendWhereCondition(item, sql);
                }
                sql.append(")");
            }
        } else {
            WhereConditionItem item = (WhereConditionItem) where;
            appendWhereItem(item, sql);
        }
    }

    public abstract void validate() throws ValidateException;

    private void appendWhereItem(WhereConditionItem item, StringBuilder sql) throws ValidateException {
        if (item.getField() == null && item.getValue() == null) {
            throw new ValidateException("where condition item is empty", "where的子项为空");
        }
        sql.append(item.getField()).append(" ").append(item.getOperator().getValue()).append(" ");
        Object value = item.getValue();
        if (value instanceof String) {
            sql.append("'").append(item.getValue()).append("'");
        } else {
            sql.append(item.getValue());
        }

    }

    public Object execute(Storage storage, String table, String pattern, Integer maxBatchSize) throws Exception {
        validate();
        if (storage.getType() != null) {
            switch (storage.getType()) {
                case ES:
                    return executeES(storage, table, pattern, maxBatchSize);
                case Redis:
                    return executeRedis(storage, table, maxBatchSize);
            }
        }
        return executeDB(storage, table, maxBatchSize);
    }

    protected boolean isFieldsValid(List<String> list) {
        boolean valid = isValid(list);
        if (!valid) {
            return false;
        }
        if (list.size() == 0 && list.get(0).trim().equals("*")) {
            return false;
        }
        return true;
    }

    protected void appendFields(StringBuilder sql, List<String> fields) {
        if (isFieldsValid(fields)) {
            for (String field : fields) {
                if (StringUtils.isEmpty(field)) {
                    continue;
                }
                sql.append(field).append(",");
            }
            sql.deleteCharAt(sql.length() - 1);
        } else {
            sql.append("*");
        }
    }

    protected abstract Object executeDB(Storage storage, String table, Integer maxBatchSize) throws Exception;

    protected abstract Object executeRedis(Storage storage, String table, Integer maxBatchSize) throws Exception;

    protected Object executeES(Storage storage, String table, String pattern, Integer maxBatchSize) throws Exception {
        boolean isOk = esUtils.esMapping(table, pattern, storage);
        LOG.info("ES Mapping read");
        if (!isOk) throw new ValidateException("Fail to find " + table + " Mappings!",
                "无法读取表"+ table + "的Mappings!" );
        return isOk;
    }


    protected void validate(BaseParam param) throws ValidateException {
        if (param.getWhere() != null) {
            try{
                WhereConditionGroup conditions = (WhereConditionGroup)param.getWhere();
            }catch(ClassCastException e){
                throw new ValidateException("where conditions must not empty",
                        "where条件组的conditions不能为空");
            }
            validate(param.getWhere());
        }
    }

    protected void validate(WhereConditionGroup where) throws ValidateException {
        if (where.getConditions() == null || where.getConditions().size() == 0) {
            throw new ValidateException("where conditions must not empty",
                    "where条件组的conditions不能为空");
        }
        if (where.getOperator() == null)
            throw new ValidateException("where Operator must not empty " +
                    "or must be [and, or, not]",
                "where条件组的Operator不能为空或者只能为 and, or, not");

        for (WhereCondition whereCondition : where.getConditions()) {
            validate(whereCondition);
        }
    }

    protected void validate(WhereConditionItem where) throws ValidateException {
        if (where.getOperator() == null) {
            throw new ValidateException("where condition's operator must not empty " +
                    "or must be [>, >=, <, <=, =, !=, like]",
                    "where条件的operator不能为空或者只能为 >, >=, <, <=, =, !=, like");
        }
        if (StringUtils.isEmpty(where.getField())) {
            throw new ValidateException("where condition's field must not empty",
                    "where条件的field不能为空");
        }
    }

    protected void validate(WhereCondition whereCondition) throws ValidateException {
        if (whereCondition instanceof WhereConditionGroup) {
            validate((WhereConditionGroup) whereCondition);
        } else {
            validate((WhereConditionItem) whereCondition);
        }
    }

    protected void validateFields(List<String> fields) throws ValidateException {
        boolean flag1 = false;
        boolean flag2 = false;
        int counter = 0;
        if (fields != null) {
            for (String field : fields) {
                if (StringUtils.isEmpty(field)) {
                    continue;
                }else{
                    counter ++;
                }
                if (field.trim().equals("*")) {
                    flag1 = true;
                } else {
                    flag2 = true;
                }
            }
            if (flag1 && flag2) {
                throw new ValidateException("fields must not both contains * and not * field",
                        "fields不能同时包含*和非*字段");
            }
            if (counter == 0){
                throw new ValidateException("fields must be available field in table",
                        "fields必须为表中的有效字段！");
            }
        }

    }

    protected void validateLimit(Integer limit) throws ValidateException {
        if (limit == null) {
            throw new ValidateException("limit must not empty", "limit不能为空");
        }
    }

    protected void validateOrderBy(Map<String, OrderType> orderBy) throws ValidateException {
        if (orderBy == null || orderBy.size() == 0) {
            return;
        }
        for (Map.Entry<String, OrderType> entry : orderBy.entrySet()) {
            if (!Constants.fieldPattern.matcher(entry.getKey()).matches()) {
                throw new ValidateException("order by field must match regex: " + Constants.fieldPattern.pattern(),
                        "order by field必须匹配正则：" + Constants.fieldPattern.pattern());
            }

            if (entry.getValue() == null){
                    throw new ValidateException(Constants.NOT_FOUND_PARAMS_ERROR_EN,
                            "[Ordery Type]" + Constants.NOT_FOUND_PARAMS_ERROR_CN);
            }
        }
    }
}

